/**
 * @file           : Dr16Receiver.h
 * @author         : Star_Plucking
 * @brief          : DR16接收机
 * @date           : 25-1-7 下午12:23
 * @lastEditor     :
 * @lastEditTime   : 25-1-7 下午12:23
 */

#pragma once
#include "sheriffos.h"
#include <rtos/timer.h>
#include <device.h>
#include <units.h>

using namespace units::literals;

#if DEVICE_DR16
namespace device::dr16_receiver {
#define RIGHT_X 0
#define RIGHT_Y 1
#define LEFT_X 2
#define LEFT_Y 3
#define PADDLE_WHEEL 4
#define SWITCH_LEFT 0
#define SWITCH_RIGHT 1

#define REMOTE_ANTI_DRIFT_VALUE 1
#define REMOTE_CHANNEL_VALUE_OFFSET 1024
#define REMOTE_CHANNEL_ERROR_LIMIT 700
#define REMOTE_OFFLINE_TIME 1000
#define REMOTE_RX_FRAME_LEN 18
#define REMOTE_RX_BUFF_LEN 54

enum class Receiver_StateEnum {
    REMOTE_STATE_NULL,
    REMOTE_STATE_CONNECTED,
    REMOTE_STATE_LOST,
    REMOTE_STATE_ERROR,
    REMOTE_STATE_PENDING
};

enum class Receiver_SwitchStateEnum { REMOTE_SWITCH_NULL, REMOTE_SWITCH_UP, REMOTE_SWITCH_DOWN, REMOTE_SWITCH_MIDDLE };

typedef struct {
    uint16_t w : 1;
    uint16_t s : 1;
    uint16_t a : 1;
    uint16_t d : 1;
    uint16_t shift : 1;
    uint16_t ctrl : 1;
    uint16_t q : 1;
    uint16_t e : 1;
    uint16_t r : 1;
    uint16_t f : 1;
    uint16_t g : 1;
    uint16_t z : 1;
    uint16_t x : 1;
    uint16_t c : 1;
    uint16_t v : 1;
    uint16_t b : 1;
} Keyboard_DataTypeDef;

typedef struct {
    struct {
        int16_t ch[5];
        Receiver_SwitchStateEnum s[2];
    } remote{};

    struct {
        int16_t x; // mouse x
        int16_t y; // mouse y
        int16_t z; // mouse z
        uint8_t l; // mouse Left key
        uint8_t r; // mouse Right key
    } mouse{}, mouse_last{};

    Keyboard_DataTypeDef key_board;
    Keyboard_DataTypeDef key_board_last;
} Receiver_DataTypeDef;
} // namespace device::dr16_receiver

namespace device::dr16_receiver {
class Receiver;
extern Receiver* Instance_dr16;

class Receiver {
public:
    Receiver_StateEnum state_{Receiver_StateEnum::REMOTE_STATE_NULL};
    uint16_t mouse_x_{0}, mouse_y_{0}, mouse_z_{0};
    uint8_t rx_buff_[REMOTE_RX_BUFF_LEN]{};
    uint64_t last_update_time_{0};
    Receiver_DataTypeDef m_data{};

private:
    explicit Receiver() {
    };

public:
    // 单例，禁止拷贝
    Receiver(Receiver const&) = delete;
    Receiver& operator=(Receiver const&) = delete;

    ~Receiver() {
    };

    static Receiver& Instance() {
        static Receiver instance;
        Instance_dr16 = &instance;
        return instance;
    }

    os::Timer connectGuard{500_ms, os::Timer::ReloadOption::kNoAutoReload, os::Timer::StartOption::kNoAutoStart,
                           [&](uint32_t) { state_ = Receiver_StateEnum::REMOTE_STATE_LOST; }};

    /**
     * @brief  Remove remote control offset
     * @param ch :Original channel value
     * @return True value
     */
    static int16_t CancelOffset(uint16_t const ch) { return static_cast<int16_t>(ch) - REMOTE_CHANNEL_VALUE_OFFSET; }

    /**
     * @brief      Judge whether the remote control data is wrong
     * @retval     True: Wrong
     */
    bool IsError() {
        for (int i = 0; i < 5; ++i) {
            if (abs(m_data.remote.ch[i]) > REMOTE_CHANNEL_ERROR_LIMIT) {
                state_ = Receiver_StateEnum::REMOTE_STATE_ERROR;
            }
        }
        for (int i = 0; i < 2; ++i) {
            if (m_data.remote.s[i] == Receiver_SwitchStateEnum::REMOTE_SWITCH_NULL) {
                state_ = Receiver_StateEnum::REMOTE_STATE_ERROR;
            }
        }
        if (state_ == Receiver_StateEnum::REMOTE_STATE_ERROR)
            return true;
        else
            return false;
    }

    /**
     * @brief      Initialize remote control data
     * @retval     NULL
     */
    void Reset() {
        for (int i = 0; i < 5; ++i) {
            m_data.remote.ch[i] = 0;
        }
        for (int i = 0; i < 2; ++i) {
            m_data.remote.s[i] = Receiver_SwitchStateEnum::REMOTE_SWITCH_NULL;
        }
        m_data.mouse.x = 0;
        m_data.mouse.y = 0;
        m_data.mouse.z = 0;
        m_data.mouse.l = 0;
        m_data.mouse.r = 0;
        memset(&m_data.key_board, 0, sizeof(Keyboard_DataTypeDef));
    }

    /**
     * @brief 遥控器数据解码
     * @param buff
     * @param data_length
     */
    void DecodeData(uint8_t const* buff, int const data_length) {
        if (data_length != REMOTE_RX_FRAME_LEN) {
            return;
        }
        UNUSED(connectGuard.stopSafe());
        state_ = Receiver_StateEnum::REMOTE_STATE_PENDING;
        m_data.mouse_last = m_data.mouse;
        m_data.key_board_last = m_data.key_board;
        last_update_time_ = os::getTime().value();

        m_data.remote.ch[RIGHT_X] =
            CancelOffset((static_cast<uint16_t>(buff[0]) | static_cast<uint16_t>(buff[1]) << 8) & 0x07FF);
        m_data.remote.ch[RIGHT_Y] =
            CancelOffset((static_cast<uint16_t>(buff[1]) >> 3 | static_cast<uint16_t>(buff[2]) << 5) & 0x07FF);
        m_data.remote.ch[LEFT_X] =
            CancelOffset((static_cast<uint16_t>(buff[2]) >> 6 | static_cast<uint16_t>(buff[3]) << 2 |
                          static_cast<uint16_t>(buff[4]) << 10) &
                         0x07FF);
        m_data.remote.ch[LEFT_Y] =
            CancelOffset((static_cast<uint16_t>(buff[4]) >> 1 | static_cast<uint16_t>(buff[5]) << 7) & 0x07FF);
        m_data.remote.ch[PADDLE_WHEEL] =
            CancelOffset((static_cast<uint16_t>(buff[16]) | static_cast<uint16_t>(buff[17]) << 8) & 0x07FF);
        m_data.remote.s[SWITCH_LEFT] = static_cast<Receiver_SwitchStateEnum>((buff[5] >> 6) & 0x03);
        m_data.remote.s[SWITCH_RIGHT] = static_cast<Receiver_SwitchStateEnum>((buff[5] >> 4) & 0x03);
        m_data.mouse.x = static_cast<int16_t>(buff[6]) | static_cast<int16_t>(buff[7]) << 8;
        m_data.mouse.y = static_cast<int16_t>(buff[8]) | static_cast<int16_t>(buff[9]) << 8;
        m_data.mouse.z = static_cast<int16_t>(buff[10]) | static_cast<int16_t>(buff[11]) << 8;
        m_data.mouse.l = buff[12];
        m_data.mouse.r = buff[13];

        uint16_t const temp = static_cast<int16_t>(buff[14]) | static_cast<int16_t>(buff[15]) << 8;
        memcpy(&m_data.key_board, &temp, sizeof(uint16_t));

        if (m_data.remote.ch[PADDLE_WHEEL] == -1024) {
            m_data.remote.ch[PADDLE_WHEEL] = 0;
        }

        if (IsError()) {
            state_ = Receiver_StateEnum::REMOTE_STATE_ERROR;
            Reset();
            return;
        }
        state_ = Receiver_StateEnum::REMOTE_STATE_CONNECTED;

        UNUSED(connectGuard.startSafe());
    }
};
} // namespace device::dr16_receiver

#endif